-
Notifications
You must be signed in to change notification settings - Fork 0
실전 자바 소프트웨어 개발 Chapter4 학습 #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis update introduces a comprehensive document management system example for educational purposes, including conceptual documentation, Java source code, and a complete Gradle project setup with tests and reports. Additional minor changes include the creation of placeholder classes for networking and servlet infrastructure, a percent encoding demonstration, and minor configuration and logging adjustments in other unrelated modules. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DocumentManagementSystem
participant Importer
participant Document
User->>DocumentManagementSystem: importFile(path)
DocumentManagementSystem->>Importer: importFile(file)
Importer-->>Document: (creates Document with attributes)
Importer-->>DocumentManagementSystem: return Document
DocumentManagementSystem-->>User: (Document added to contents)
User->>DocumentManagementSystem: search(query)
DocumentManagementSystem->>Document: getAttribute()
DocumentManagementSystem-->>User: return matching Documents
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 25
🧹 Nitpick comments (34)
thread-pool-optimization/k6/io_user_test.js (1)
16-22: Great enhancement to error diagnostics!The modification to the status check improves observability by adding detailed error logging while preserving the original functionality. When an HTTP request fails, you'll now see the status code, status text, and response headers, making debugging much easier.
A small suggestion for even better diagnostics would be to include the response body in the error log for cases where the API returns error details in the body.
'status is 200': (r) => { const ok = r.status === 200; if (!ok) { - console.log(`❌ 실패 응답: ${r.status} ${r.status_text}, headers: ${JSON.stringify(r.headers)}`); + console.log(`❌ 실패 응답: ${r.status} ${r.status_text}, headers: ${JSON.stringify(r.headers)}, body: ${r.body}`); } return ok; },javav-network/src/main/java/project/reflect/caculator/Calculator.java (1)
3-5: Add class-level Javadoc stub.As an empty placeholder class, include a brief Javadoc describing its intended role or planned methods. This improves discoverability and sets clear expectations for future development. For example:
/** * Calculator provides core arithmetic operations for reflection-based utilities. * <p> * Future implementations may include methods like add, subtract, multiply, and divide. * </p> */ public class Calculator { // ... }javav-network/src/main/java/project/was/v3/PercentEncodingMain.java (2)
9-10: Consider renaming variables for clarity.
To improve readability, renameencode→encoded(orencodedString) anddecode→decoded(ordecodedString), since these store processed values.Proposed diff:
- String encode = URLEncoder.encode("가%", StandardCharsets.UTF_8); + String encoded = URLEncoder.encode("가%", StandardCharsets.UTF_8); - System.out.println("encode = " + encode); + System.out.println("encoded = " + encoded); - String decode = URLDecoder.decode(encode, StandardCharsets.UTF_8); + String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8); - System.out.println("decode = " + decode); + System.out.println("decoded = " + decoded);Also applies to: 12-13
7-8: Add a brief class-level Javadoc.
Since this is a public utility/demo, a short Javadoc enhances discoverability in IDEs and generated docs.Proposed addition:
+/** + * Demonstrates percent-encoding and decoding of a sample string using UTF-8. + */ public class PercentEncodingMain {thread-pool-optimization/src/main/java/project/threadpooloptimization/interfaces/UserController.java (1)
9-11: Remove or justify unused imports
The importsHandlerMethod,RequestMappingHandlerAdapter, andRequestMappingHandlerMappingare not used anywhere in this controller. Unused imports increase clutter and can confuse maintainers. If they’re planned for imminent use, please add a comment explaining their purpose; otherwise, remove them.thread-pool-optimization/src/main/resources/application.yml (1)
4-6: Clarify the commentedaccept-countsetting
Commenting outaccept-count: 300causes Tomcat to revert to its default backlog (usually 100). If you intend to support a backlog of 300 connections, uncomment or explicitly set this value. Otherwise, consider removing the commented line to avoid confusion.javav-network/src/main/java/project/was/httpserver/ServletManager.java (2)
11-13: Consider adding validation in theaddmethod.The current implementation allows overwriting existing servlet mappings without any warning or validation. Consider adding validation to prevent accidentally overwriting existing mappings or to explicitly document this behavior.
public void add(String path, HttpServlet servlet){ + if (servletMap.containsKey(path)) { + // Option 1: Throw exception + // throw new IllegalArgumentException("Servlet mapping already exists for path: " + path); + + // Option 2: Log warning + // System.out.println("Warning: Overwriting existing servlet mapping for path: " + path); + } + if (servlet == null) { + throw new IllegalArgumentException("Servlet cannot be null"); + } servletMap.put(path, servlet); }
1-22: Add JavaDoc comments for better documentation.The class and its methods lack documentation. Adding JavaDoc comments would improve code maintainability and help other developers understand the purpose and usage of this class.
package project.was.httpserver; import java.util.HashMap; import java.util.Map; +/** + * Manages servlet registrations and dispatches HTTP requests to the appropriate servlet. + * Serves as the central registry for mapping URL paths to servlet instances. + */ public class ServletManager { private final Map<String, HttpServlet> servletMap = new HashMap<>(); + /** + * Registers a servlet for a specific URL path. + * + * @param path The URL path to map the servlet to + * @param servlet The servlet instance to handle requests to the specified path + */ public void add(String path, HttpServlet servlet){ servletMap.put(path, servlet); } + /** + * Executes the appropriate servlet based on the incoming request. + * If no servlet is registered for the requested path, a 404 response is generated. + * + * @param request The HTTP request to process + * @param response The HTTP response to populate + */ public void execute(HttpRequest request, HttpResponse response){ try{ }catch (Exception e){ } } }book/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.properties (1)
1-6: Timestamp in the future detectedThe timestamp in line 1 shows "Sat May 17 10:03:06 KST 2025" which appears to be in the future. While this doesn't affect functionality, it might indicate an incorrect system clock when this file was generated.
Otherwise, the Gradle wrapper configuration is standard and correctly configured with Gradle 8.5.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
4-14: Good use of constants class but add private constructorCentralizing string constants is good practice to prevent duplication and typos. However, utility classes with only static members should typically have a private constructor to prevent instantiation.
Add a private constructor to prevent instantiation:
public final class Attributes { + private Attributes() { + // Prevents instantiation + } + public static final String PATH = "path"; public static final String PATIENT = "patient"; public static final String ADDRESS = "address"; public static final String BODY = "body"; public static final String WIDTH = "width"; public static final String HEIGHT = "height"; public static final String TYPE = "type"; public static final String AMOUNT = "amount"; }book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java (2)
12-14: Add null check and consider additional methodsThe getAttribute method should validate the input parameter. Also, consider adding methods to check if an attribute exists or to get all attributes.
Add null validation and consider additional helper methods:
public String getAttribute(final String attributeName) { + if (attributeName == null) { + throw new IllegalArgumentException("Attribute name cannot be null"); + } return attributes.get(attributeName); } + + public boolean hasAttribute(final String attributeName) { + return attributeName != null && attributes.containsKey(attributeName); + } + + public Map<String, String> getAttributes() { + return new HashMap<>(attributes); + }
8-8: Document constructor visibility intentionThe constructor has package-private visibility. If this is intentional to restrict instantiation to within the package, consider adding a comment to make this clear.
- Document(Map<String, String> attributes) { + // Package-private constructor to restrict instantiation to within this package + Document(Map<String, String> attributes) {book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java (2)
21-21: Extract "IMAGE" as a constantThe string "IMAGE" is hardcoded in the importFile method. Consider extracting it to a constant for better maintainability.
package project; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import static project.Attributes.*; public class ImageImporter implements Importer{ + private static final String IMAGE_TYPE = "IMAGE"; @Override public Document importFile(File file) throws IOException { final Map<String, String> attributes = new HashMap<>(); attributes.put(PATH, file.getPath()); final BufferedImage image = ImageIO.read(file); attributes.put(WIDTH, String.valueOf(image.getWidth())); attributes.put(HEIGHT, String.valueOf(image.getHeight())); - attributes.put(TYPE, "IMAGE"); + attributes.put(TYPE, IMAGE_TYPE); return new Document(attributes); }
11-11: Add space after class name and interface nameThere should be a space between the class name and the opening curly brace, as well as between
implementsandImporter.-public class ImageImporter implements Importer{ +public class ImageImporter implements Importer {book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html (1)
134-135: Consider using HTTPS for external links.The link to Gradle should use HTTPS instead of HTTP for improved security.
-<a href="http://www.gradle.org">Gradle 8.5</a> +<a href="https://www.gradle.org">Gradle 8.5</a>🧰 Tools
🪛 ast-grep (0.38.1)
[warning] 134-134: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html(plaintext-http-link-html)
book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java (2)
23-23: Consider using a constant for document type.For consistency and to avoid magic strings, define a constant for the document type value.
+private static final String INVOICE_TYPE = "INVOICE"; @Override public Document importFile(final File file) throws IOException { // ... existing code final Map<String, String> attributes = textFile.getAttributes(); - attributes.put(TYPE, "INVOICE"); + attributes.put(TYPE, INVOICE_TYPE); return new Document(attributes); }
10-16: Add documentation about expected file format.Adding a class-level Javadoc comment with information about the expected format of invoice files would improve maintainability.
+/** + * Imports invoice documents assuming the following format: + * - Contains a line starting with "Dear " followed by the patient name + * - Contains a line starting with "Amount: " followed by the invoice amount + */ class InvoiceImporter implements Importer { private static final String NAME_PREFIX = "Dear "; private static final String AMOUNT_PREFIX = "Amount: ";book/real-world-software-development/chapter4/document-management/src/main/java/project/LetterImporter.java (2)
23-23: Consider using a constant for document type.For consistency and to avoid magic strings, define a constant for the document type value.
+private static final String LETTER_TYPE = "LETTER"; @Override public Document importFile(final File file) throws IOException { // ... existing code final Map<String, String> attributes = textFile.getAttributes(); - attributes.put(TYPE, "LETTER"); + attributes.put(TYPE, LETTER_TYPE); return new Document(attributes); }
10-14: Add documentation about expected file format.Adding a class-level Javadoc comment with information about the expected format of letter files would improve maintainability.
+/** + * Imports letter documents assuming the following format: + * - Contains a line starting with "Dear " followed by the patient name + * - Address starts at line 2 and continues until an empty line is found + * - Body starts after the address and continues until a line starting with "regards," + */ class LetterImporter implements Importer { private static final String NAME_PREFIX = "Dear ";book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java (3)
17-17: Improve readability of the line predicate.Using
line -> falseas a predicate is a bit cryptic. Replace it with a more descriptive approach that clarifies the intent.-textFile.addLines(2, line -> false, BODY); +// Capture all remaining lines as the body (predicate never returns true) +textFile.addLines(2, line -> false, BODY);Alternatively, consider creating a named method:
+private boolean neverStop(String line) { + return false; // Continue processing until end of file +} @Override public Document importFile(final File file) throws IOException { final TextFile textFile = new TextFile(file); textFile.addLineSuffix(NAME_PREFIX, PATIENT); - textFile.addLines(2, line -> false, BODY); + textFile.addLines(2, this::neverStop, BODY);
20-20: Consider using a constant for document type.For consistency and to avoid magic strings, define a constant for the document type value.
+private static final String REPORT_TYPE = "REPORT"; @Override public Document importFile(final File file) throws IOException { // ... existing code final Map<String, String> attributes = textFile.getAttributes(); - attributes.put(TYPE, "REPORT"); + attributes.put(TYPE, REPORT_TYPE); return new Document(attributes); }
10-14: Add documentation about expected file format.Adding a class-level Javadoc comment with information about the expected format of report files would improve maintainability.
+/** + * Imports report documents assuming the following format: + * - Contains a line starting with "Patient: " followed by the patient name + * - All content from line 2 onwards is captured as the body + */ class ReportImporter implements Importer { private static final String NAME_PREFIX = "Patient: ";book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java (1)
22-31: Consider case-insensitive matching and trimming whitespace.The current implementation uses exact string matching with
contains(), which might not be user-friendly. Consider adding options for case-insensitive matching and trimming whitespace for more flexible searching.@Override public boolean test(final Document document) { return clauses.entrySet() .stream() .allMatch(entry -> { final String documentValue = document.getAttribute(entry.getKey()); final String queryValue = entry.getValue(); - return documentValue != null && documentValue.contains(queryValue); + return documentValue != null && + documentValue.toLowerCase().contains(queryValue.toLowerCase().trim()); }); }book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java (2)
30-48: Optimize memory usage inaddLinesmethod.The method builds a potentially large string in memory using StringBuilder. For very large files, this could cause memory issues. Additionally, there's no validation for the starting index.
int addLines( final int start, final Predicate<String> isEnd, final String attributeName) { + // Validate input parameters + if (start < 0 || start >= lines.size()) { + throw new IllegalArgumentException("Invalid start index: " + start); + } + if (isEnd == null) { + throw new IllegalArgumentException("Predicate cannot be null"); + } + if (attributeName == null || attributeName.isEmpty()) { + throw new IllegalArgumentException("Attribute name cannot be null or empty"); + } final StringBuilder accumulator = new StringBuilder(); int lineNumber; for (lineNumber = start; lineNumber < lines.size(); lineNumber++) { final String line = lines.get(lineNumber); if (isEnd.test(line)) { break; } accumulator.append(line); accumulator.append("\n"); } attributes.put(attributeName, accumulator.toString().trim()); return lineNumber; }
50-57: Return result ofaddLineSuffixoperation for better caller feedback.The
addLineSuffixmethod silently fails if it can't find a line starting with the prefix. Consider returning a boolean indicating success or failure, or throw an exception for critical scenarios.-void addLineSuffix(final String prefix, final String attributeName) { +boolean addLineSuffix(final String prefix, final String attributeName) { + if (prefix == null || attributeName == null) { + throw new IllegalArgumentException("Prefix and attribute name cannot be null"); + } + for(final String line: lines) { if (line.startsWith(prefix)) { attributes.put(attributeName, line.substring(prefix.length())); - break; + return true; } } + return false; }book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (3)
11-25: Good class structure with proper encapsulationThe class follows good object-oriented design principles with:
- Private mutable list with public immutable view (defensive programming)
- Strategy pattern for importers using a map of file extensions
- Clear separation of concerns via the Importer interface
Consider consolidating the instance initializer block with the constructor for better readability and maintainability.
public DocumentManagementSystem() { extensionToImporter.put("letter", new LetterImporter()); extensionToImporter.put("report", new ReportImporter()); extensionToImporter.put("jpg", new ImageImporter()); + extensionToImporter.put("invoice", new InvoiceImporter()); } -{ - extensionToImporter.put("invoice", new InvoiceImporter()); -}
27-49: Simplify extension check logic and standardize error messagesThe implementation correctly validates files and handles appropriate exceptions. However, there's some redundancy in the extension validation logic, and the error messages aren't consistent.
public void importFile(final String path) throws IOException { final File file = new File(path); if (!file.exists()) { throw new FileNotFoundException(path); } final int separatorIndex = path.lastIndexOf('.'); - if (separatorIndex != -1) { - if (separatorIndex == path.length()) { - throw new UnknownFileTypeException("No extension found For file: " + path); - } + if (separatorIndex != -1 && separatorIndex < path.length() - 1) { final String extension = path.substring(separatorIndex + 1); final Importer importer = extensionToImporter.get(extension); if (importer == null) { - throw new UnknownFileTypeException("For file: " + path); + throw new UnknownFileTypeException("Unknown extension for file: " + path); } final Document document = importer.importFile(file); documents.add(document); } else { throw new UnknownFileTypeException("No extension found For file: " + path); } }
51-59: Consider adding Javadoc for public methodsThe search method leverages Java 8 streams and the Query class effectively. Add documentation to improve code readability and maintainability.
+/** + * Returns an unmodifiable view of all documents in the system. + * + * @return List of documents + */ public List<Document> contents() { return documentsView; } +/** + * Searches for documents matching the specified query string. + * The query format is "key:value,key:value" where keys are document attributes. + * + * @param query the query string to search for + * @return List of matching documents + */ public List<Document> search(final String query) { return documents.stream() .filter(Query.parse(query)) .collect(Collectors.toList()); }book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html (1)
479-480: Use HTTPS links for securityUpdate the Gradle link to use HTTPS instead of HTTP for better security.
-<a href="http://www.gradle.org">Gradle 8.5</a> +<a href="https://www.gradle.org">Gradle 8.5</a>🧰 Tools
🪛 ast-grep (0.38.1)
[warning] 479-479: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html(plaintext-http-link-html)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js (2)
1-3: Remove redundant 'use strict' directiveJavaScript modules automatically run in strict mode without needing the directive.
(function (window, document) { - "use strict"; var tabs = {};🧰 Tools
🪛 Biome (1.9.4)
[error] 2-2: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.(lint/suspicious/noRedundantUseStrict)
14-28: Consider using modern DOM manipulation methodsThe code works but uses older DOM manipulation approaches. Consider using modern methods like
classListinstead of directly manipulating class attributes.function getClassAttribute(element) { - if (element.getAttribute("className")) { - return element.getAttribute("className"); - } else { - return element.getAttribute("class"); - } + return element.className; } function addClass(element, classValue) { - changeElementClass(element, getClassAttribute(element) + " " + classValue); + element.classList.add(classValue); } function removeClass(element, classValue) { - changeElementClass(element, getClassAttribute(element).replace(classValue, "")); + element.classList.remove(classValue); }book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (1)
1-1: Fix package name typo.The package name
chpater4contains a typo and should bechapter4instead.-package chpater4; +package chapter4;book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css (2)
104-105: Remove empty CSS rule.The CSS rule for
div.tabis empty and doesn't serve any purpose. Consider removing it or adding the necessary styles.-div.tab { -}🧰 Tools
🪛 Biome (1.9.4)
[error] 104-105: An empty block isn't allowed.
Consider removing the empty block or adding styles inside it.
(lint/suspicious/noEmptyBlock)
1-179: Consider excluding auto-generated CSS files from version control.This appears to be an auto-generated CSS file from test reports. Consider whether it's necessary to include this in version control, as these files are typically regenerated when tests are run. You might want to add build output directories to your
.gitignorefile.Would you like me to propose a suitable
.gitignoreconfiguration for excluding build outputs?🧰 Tools
🪛 Biome (1.9.4)
[error] 104-105: An empty block isn't allowed.
Consider removing the empty block or adding styles inside it.
(lint/suspicious/noEmptyBlock)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
⛔ Files ignored due to path filters (17)
book/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Attributes.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Document.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/DocumentManagementSystem.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/ImageImporter.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Importer.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/InvoiceImporter.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/LetterImporter.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/Query.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/ReportImporter.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/TextFile.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/main/project/UnknownFileTypeException.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/classes/java/test/chpater4/DocumentManagementSystemTest.classis excluded by!**/*.classbook/real-world-software-development/chapter4/document-management/build/test-results/test/binary/output.binis excluded by!**/*.binbook/real-world-software-development/chapter4/document-management/build/test-results/test/binary/results.binis excluded by!**/*.binbook/real-world-software-development/chapter4/document-management/build/tmp/compileJava/previous-compilation-data.binis excluded by!**/*.binbook/real-world-software-development/chapter4/document-management/build/tmp/compileTestJava/previous-compilation-data.binis excluded by!**/*.binbook/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.jaris excluded by!**/*.jar
📒 Files selected for processing (37)
book/real-world-software-development/chapter4/README.md(1 hunks)book/real-world-software-development/chapter4/document-management/build.gradle.kts(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/style.css(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js(1 hunks)book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html(1 hunks)book/real-world-software-development/chapter4/document-management/build/test-results/test/TEST-chpater4.DocumentManagementSystemTest.xml(1 hunks)book/real-world-software-development/chapter4/document-management/gradle/wrapper/gradle-wrapper.properties(1 hunks)book/real-world-software-development/chapter4/document-management/gradlew(1 hunks)book/real-world-software-development/chapter4/document-management/gradlew.bat(1 hunks)book/real-world-software-development/chapter4/document-management/settings.gradle.kts(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/Importer.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/LetterImporter.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java(1 hunks)book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java(1 hunks)javav-network/src/main/java/project/reflect/caculator/Calculator.java(1 hunks)javav-network/src/main/java/project/was/httpserver/HttpRequest.java(1 hunks)javav-network/src/main/java/project/was/httpserver/HttpResponse.java(1 hunks)javav-network/src/main/java/project/was/httpserver/HttpServlet.java(1 hunks)javav-network/src/main/java/project/was/httpserver/ServletManager.java(1 hunks)javav-network/src/main/java/project/was/httpserver/servlet/NotFoundServlet.java(1 hunks)javav-network/src/main/java/project/was/v3/PercentEncodingMain.java(1 hunks)javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java(1 hunks)simple-java/docs/chapter4.md(1 hunks)thread-pool-optimization/k6/io_user_test.js(1 hunks)thread-pool-optimization/src/main/java/project/threadpooloptimization/interfaces/UserController.java(1 hunks)thread-pool-optimization/src/main/resources/application.yml(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
javav-network/src/main/java/project/was/httpserver/HttpServlet.java (1)
javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java (1)
HttpServlet(3-4)
book/real-world-software-development/chapter4/document-management/src/main/java/project/ReportImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
Attributes(4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/ImageImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
Attributes(4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Query.java (1)
Query(9-32)
book/real-world-software-development/chapter4/document-management/src/main/java/project/TextFile.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
Attributes(4-14)
book/real-world-software-development/chapter4/document-management/src/main/java/project/InvoiceImporter.java (1)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
Attributes(4-14)
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (4)
book/real-world-software-development/chapter4/document-management/src/main/java/project/Document.java (1)
Document(5-16)book/real-world-software-development/chapter4/document-management/src/main/java/project/DocumentManagementSystem.java (1)
DocumentManagementSystem(11-60)book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java (1)
UnknownFileTypeException(3-7)book/real-world-software-development/chapter4/document-management/src/main/java/project/Attributes.java (1)
Attributes(4-14)
🪛 ast-grep (0.38.1)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html
[warning] 134-134: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html
(plaintext-http-link-html)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html
[warning] 164-164: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html
(plaintext-http-link-html)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html
[warning] 479-479: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html
(plaintext-http-link-html)
🪛 Biome (1.9.4)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/base-style.css
[error] 104-105: An empty block isn't allowed.
Consider removing the empty block or adding styles inside it.
(lint/suspicious/noEmptyBlock)
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js
[error] 2-2: Redundant use strict directive.
The entire contents of JavaScript modules are automatically in strict mode, with no statement needed to initiate it.
Safe fix: Remove the redundant use strict directive.
(lint/suspicious/noRedundantUseStrict)
🔇 Additional comments (21)
javav-network/src/main/java/project/was/v3/PercentEncodingMain.java (1)
9-13: Encoding and decoding logic is correct.
The use ofURLEncoder.encodeandURLDecoder.decodewithStandardCharsets.UTF_8correctly demonstrates percent-encoding/decoding in UTF-8.javav-network/src/main/java/project/was/httpserver/ServletManager.java (1)
6-9: Good use of proper encapsulation for servlet registry.The
ServletManagerclass correctly uses a private final Map for storing servlet mappings, which prevents external modification of the collection reference and enforces access control through the provided methods.book/real-world-software-development/chapter4/document-management/settings.gradle.kts (1)
1-2: LGTM!The settings file correctly sets the root project name to "document-management". This follows standard Gradle project configuration practices.
book/real-world-software-development/chapter4/document-management/src/main/java/project/Importer.java (1)
6-8: LGTM! Good interface design.The
Importerinterface is well-designed with a single, clear responsibility. It follows the Single Responsibility Principle by focusing only on importing documents from files. The method signature properly declares the checkedIOExceptionthat implementations might throw.book/real-world-software-development/chapter4/document-management/build.gradle.kts (1)
12-21: LGTM! Dependencies are well-organized.Good job organizing the test dependencies with clear comments for each group. Including both JUnit 5 and Hamcrest provides a comprehensive testing toolkit.
book/real-world-software-development/chapter4/document-management/src/main/java/project/UnknownFileTypeException.java (1)
3-7: LGTM! Well-designed exception class.The exception class follows good practices:
- Descriptive name that clearly communicates its purpose
- Extends the appropriate base class (RuntimeException)
- Provides a constructor that passes the message to the parent class
This unchecked exception is appropriate for signaling programming errors like attempting to import an unsupported file type.
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/css/style.css (1)
1-85: Auto-generated file - no review neededThis CSS file is auto-generated by Gradle's test reporting mechanism and not intended for manual editing. It follows standard CSS practices for styling test report elements.
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/packages/chpater4.html (1)
31-32: Note the high test failure rate.7 out of 8 tests are failing, suggesting significant issues with the implementation or test expectations. This might be expected for an educational project, but should be addressed before considering the code complete.
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/index.html (1)
1-169: Test failures indicate missing test resource files.The test report shows 7 failed tests out of 8, with a 12% success rate. Most failures appear to be due to missing test resource files in the
src/test/resourcesdirectory.Create the required test resource files in the appropriate directory to make the tests pass.
🧰 Tools
🪛 ast-grep (0.38.1)
[warning] 164-164: "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible."
Context: Gradle 8.5
Note: [CWE-319] Authentication Bypass by Primary Weakness [REFERENCES]
- https://cwe.mitre.org/data/definitions/319.html(plaintext-http-link-html)
book/real-world-software-development/chapter4/document-management/gradlew.bat (1)
1-89: Standard Gradle wrapper script with proper setupThis is a standard Gradle wrapper batch script for Windows, which follows best practices for Gradle project setup.
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java (4)
59-63: Good use of test data and assertion methods.The test properly verifies multiple attributes of the letter document, ensuring that the LetterImporter correctly extracts all required information. This aligns with the strong typing principle mentioned in the PR objectives.
101-111: Well-implemented search functionality test.This test effectively demonstrates searching for documents by multiple attributes (patient name and body content), verifying the Query parsing and filtering functionality. Good example of the practical implementation of the domain classes concept mentioned in the README.
114-125: Good error handling test cases.These tests verify appropriate exception handling for missing files and unknown file types, which is important for robust error management. This follows good testing practices by ensuring failure cases are handled properly.
137-148: Well-structured helper method for assertions.The
assertAttributeEqualsmethod provides clear error messages and reduces code duplication, making the tests more maintainable. This demonstrates good test hygiene as mentioned in the PR objectives.book/real-world-software-development/chapter4/README.md (6)
1-13: Clear requirement specification.The requirements section effectively outlines the core functionality needed for the document management system: reading existing patient files, adding indexing, and enabling search across different document types (reports, mail, images). It also specifies the need for extensibility, which aligns with the composition over inheritance principle mentioned in the PR objectives.
18-20: Good explanation of switch statement limitations.This section correctly identifies the extensibility problem with switch statements, which is a practical example of why composition is preferred over procedural approaches. This directly relates to the composition over inheritance principle mentioned in the PR objectives.
21-24: Well-articulated strong typing principles.The explanation of strong typing principles and immutable objects aligns with the PR objectives. It correctly highlights how these principles help localize errors and enable safe indexing and caching of documents.
32-35: Good explanation of ubiquitous language.This section effectively explains the concept of ubiquitous language and how it improves communication between developers and customers by using consistent terminology. This directly supports the PR objective regarding ubiquitous language.
40-48: Comprehensive explanation of Liskov Substitution Principle.The detailed explanation of LSP with its four main rules provides a clear understanding of proper inheritance and interface implementation. This aligns with the PR objectives about LSP and provides valuable guidelines for the implementation.
52-66: Thorough discussion of code reuse methods.This section effectively covers the three ways to reuse code mentioned in the PR objectives (utility classes, inheritance, and domain classes), including the pros and cons of each approach. The warning about improper inheritance is particularly valuable.
book/real-world-software-development/chapter4/document-management/gradlew (1)
1-234:Details
✅ Verification successful
Ensure Gradle wrapper has executable permissions.
This is a standard Gradle wrapper script. Make sure it has executable permissions so it can be run directly.
🏁 Script executed:
#!/bin/bash # Check if the gradlew file has executable permissions ls -la gradlew echo "Setting executable permissions" chmod +x gradlew ls -la gradlewLength of output: 291
Let’s locate the wrapper script in its actual path and verify its permissions:
🏁 Script executed:
#!/bin/bash # Locate the gradlew file anywhere in the repo wrapper=$(find . -type f -name gradlew | head -n1) if [ -z "$wrapper" ]; then echo "ERROR: gradlew not found in repository" exit 1 fi echo "Found wrapper at: $wrapper" ls -la "$wrapper" echo "Ensuring executable permissions…" chmod +x "$wrapper" ls -la "$wrapper"Length of output: 556
Verified: Gradle wrapper is already executable
The
gradlewscript located atjava-syncronized/gradlewhas-rwxr-xr-xpermissions, so no further action is needed.
| package project.reflect.caculator; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: Typo in package name.
The package declaration project.reflect.caculator (and corresponding directory caculator) is misspelled. This will lead to inconsistent imports and runtime reflection errors. Please correct both the package and directory name to calculator:
- package project.reflect.caculator;
+ package project.reflect.calculator;Rename the folder caculator → calculator to keep the filesystem in sync with the package.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package project.reflect.caculator; | |
| package project.reflect.calculator; |
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/reflect/caculator/Calculator.java at
lines 1 to 2, the package name is misspelled as "caculator". Rename the package
declaration to "project.reflect.calculator" and also rename the directory from
"caculator" to "calculator" to ensure consistency between the package name and
the filesystem structure.
| package project.was.httpserver; | ||
|
|
||
| public interface HttpServlet { | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Define the core servlet contract
The HttpServlet interface is empty, making it unusable as a servlet contract. At minimum, declare a service method that accepts HttpRequest and HttpResponse.
Apply a diff such as:
package project.was.httpserver;
+
+import project.was.httpserver.HttpRequest;
+import project.was.httpserver.HttpResponse;
public interface HttpServlet {
-}
+ /**
+ * Process an incoming HTTP request and populate the response.
+ */
+ void service(HttpRequest request, HttpResponse response);
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package project.was.httpserver; | |
| public interface HttpServlet { | |
| } | |
| package project.was.httpserver; | |
| import project.was.httpserver.HttpRequest; | |
| import project.was.httpserver.HttpResponse; | |
| public interface HttpServlet { | |
| /** | |
| * Process an incoming HTTP request and populate the response. | |
| */ | |
| void service(HttpRequest request, HttpResponse response); | |
| } |
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpServlet.java lines 1
to 4, the HttpServlet interface is currently empty and lacks a core contract.
Define a service method in the interface that takes HttpRequest and HttpResponse
parameters to establish the basic servlet contract. This will make the interface
usable for handling HTTP requests and responses.
| package project.was.v5.servlet; | ||
|
|
||
| public class HttpServlet { | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid duplicate HttpServlet definitions
There are two HttpServlet types in the codebase (httpserver.HttpServlet and v5.servlet.HttpServlet), which will cause confusion and complicate maintenance. Consider removing or renaming the versioned class, or have it implement/extend the core HttpServlet interface introduced above.
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/v5/servlet/HttpServlet.java lines 1
to 4, there is a duplicate HttpServlet class conflicting with
httpserver.HttpServlet. To fix this, either remove this versioned HttpServlet
class if it is redundant, rename it to a more specific name to avoid confusion,
or refactor it to extend or implement the core HttpServlet interface from
httpserver to maintain clear hierarchy and reduce duplication.
| package project.was.httpserver; | ||
|
|
||
| public class HttpResponse { | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance HttpResponse with response API
HttpResponse is an empty placeholder. To support real-world use, define status code, headers, and body manipulation methods.
Example diff:
package project.was.httpserver;
+
+import java.io.OutputStream;
+import java.util.Map;
+
public class HttpResponse {
-}
+ private int statusCode;
+ private Map<String, String> headers;
+ private OutputStream body;
+
+ public void setStatus(int code) { this.statusCode = code; }
+ public int getStatus() { return statusCode; }
+
+ public void addHeader(String name, String value) { headers.put(name, value); }
+ public Map<String, String> getHeaders() { return headers; }
+
+ public OutputStream getBody() { return body; }
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package project.was.httpserver; | |
| public class HttpResponse { | |
| } | |
| package project.was.httpserver; | |
| import java.io.OutputStream; | |
| import java.util.Map; | |
| public class HttpResponse { | |
| private int statusCode; | |
| private Map<String, String> headers; | |
| private OutputStream body; | |
| public void setStatus(int code) { this.statusCode = code; } | |
| public int getStatus() { return statusCode; } | |
| public void addHeader(String name, String value) { headers.put(name, value); } | |
| public Map<String, String> getHeaders() { return headers; } | |
| public OutputStream getBody() { return body; } | |
| } |
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpResponse.java at lines
1 to 4, the HttpResponse class is currently empty and lacks functionality. Add
fields to store the HTTP status code, headers (using a suitable map structure),
and the response body. Implement methods to set and get the status code, add and
retrieve headers, and set and get the response body content. This will provide a
basic but functional HTTP response API.
| package project.was.httpserver; | ||
|
|
||
| public class HttpRequest { | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance HttpRequest with request API
HttpRequest is currently empty. It should expose HTTP method, URI, headers, parameters, and input stream for a usable API.
Example diff:
package project.was.httpserver;
+
+import java.io.InputStream;
+import java.util.Map;
+
public class HttpRequest {
-}
+ private String method;
+ private String path;
+ private Map<String, String> headers;
+ private InputStream body;
+
+ public String getMethod() { return method; }
+ public String getPath() { return path; }
+
+ public String getHeader(String name) { return headers.get(name); }
+ public InputStream getBody() { return body; }
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| package project.was.httpserver; | |
| public class HttpRequest { | |
| } | |
| package project.was.httpserver; | |
| import java.io.InputStream; | |
| import java.util.Map; | |
| public class HttpRequest { | |
| private String method; | |
| private String path; | |
| private Map<String, String> headers; | |
| private InputStream body; | |
| public String getMethod() { | |
| return method; | |
| } | |
| public String getPath() { | |
| return path; | |
| } | |
| public String getHeader(String name) { | |
| return headers.get(name); | |
| } | |
| public InputStream getBody() { | |
| return body; | |
| } | |
| } |
🤖 Prompt for AI Agents
In javav-network/src/main/java/project/was/httpserver/HttpRequest.java at lines
1 to 4, the HttpRequest class is currently empty and lacks functionality.
Implement fields and methods to expose the HTTP method, URI, headers,
parameters, and input stream. This includes adding private variables for these
components and providing public getter methods to access them, enabling the
class to represent and handle HTTP request data properly.
| <failure message="java.io.FileNotFoundException: src/test/resources/patient.report" type="java.io.FileNotFoundException">java.io.FileNotFoundException: src/test/resources/patient.report | ||
| at project.DocumentManagementSystem.importFile(DocumentManagementSystem.java:30) | ||
| at chpater4.DocumentManagementSystemTest.shouldImportReportAttributes(DocumentManagementSystemTest.java:69) | ||
| at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) | ||
| at java.base/java.lang.reflect.Method.invoke(Method.java:580) | ||
| at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) | ||
| at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) | ||
| at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) | ||
| at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) | ||
| at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) | ||
| at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) | ||
| at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) | ||
| at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) | ||
| at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) | ||
| at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) | ||
| at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) | ||
| at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) | ||
| at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) | ||
| at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) | ||
| at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) | ||
| at org.junit.runners.ParentRunner.run(ParentRunner.java:413) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40) | ||
| at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60) | ||
| at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52) | ||
| at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) | ||
| at java.base/java.lang.reflect.Method.invoke(Method.java:580) | ||
| at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) | ||
| at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) | ||
| at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) | ||
| at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) | ||
| at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) | ||
| at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) | ||
| at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) | ||
| at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) | ||
| at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) | ||
| at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) | ||
| </failure> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Create missing test resources to resolve FileNotFoundException errors.
All but one test are failing due to missing resource files. These files need to be created in the src/test/resources directory:
- patient.report
- patient.invoice
- patient.letter
- xray.jpg
- unknown.txt
Also applies to: 50-92, 95-137, 140-186, 190-232, 235-277, 280-322
🏁 Script executed:
#!/bin/bash
# Check if the test resources directory exists and create it if not
mkdir -p book/real-world-software-development/chapter4/document-management/src/test/resources
# Check which test files are missing
echo "Missing test resource files:"
for file in "patient.report" "patient.invoice" "patient.letter" "xray.jpg" "unknown.txt"; do
if [ ! -f "book/real-world-software-development/chapter4/document-management/src/test/resources/$file" ]; then
echo "- $file"
fi
doneLength of output: 1393
Add missing test resource files to src/test/resources
Several tests are failing with FileNotFoundException because the following resource files are not present under
book/real-world-software-development/chapter4/document-management/src/test/resources:
- patient.report
- patient.invoice
- patient.letter
- xray.jpg
- unknown.txt
Please add these files (they can be empty or contain sample data) to the above directory so that the import tests in DocumentManagementSystemTest pass.
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/resources
around lines 5 to 47 of the test result XML, the tests fail due to missing
resource files causing FileNotFoundException. To fix this, create the missing
test resource files named patient.report, patient.invoice, patient.letter,
xray.jpg, and unknown.txt in the src/test/resources directory of the
document-management module. These files can be empty or contain sample data to
allow the import tests in DocumentManagementSystemTest to run successfully.
| <head> | ||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | ||
| <meta http-equiv="x-ua-compatible" content="IE=edge"/> | ||
| <title>Test results - Class chpater4.DocumentManagementSystemTest</title> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typo in package name
There's a typo in the package name: "chpater4" should be "chapter4".
This issue affects both the package name in your test code and the corresponding folder structure. You'll need to rename the package and update any references.
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/classes/chpater4.DocumentManagementSystemTest.html
at line 6, correct the typo in the package name from "chpater4" to "chapter4".
Rename the package declaration in the test code accordingly and update the
folder structure to match the corrected package name. Also, ensure all
references to this package in the project are updated to use "chapter4".
| <pre>java.io.FileNotFoundException: src/test/resources/patient.letter | ||
| at project.DocumentManagementSystem.importFile(DocumentManagementSystem.java:30) | ||
| at chpater4.DocumentManagementSystemTest.shouldBeAbleToSearchFilesByAttributes(DocumentManagementSystemTest.java:103) | ||
| at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) | ||
| at java.base/java.lang.reflect.Method.invoke(Method.java:580) | ||
| at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) | ||
| at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) | ||
| at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) | ||
| at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) | ||
| at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) | ||
| at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) | ||
| at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) | ||
| at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) | ||
| at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) | ||
| at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) | ||
| at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) | ||
| at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) | ||
| at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) | ||
| at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) | ||
| at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) | ||
| at org.junit.runners.ParentRunner.run(ParentRunner.java:413) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) | ||
| at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40) | ||
| at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60) | ||
| at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52) | ||
| at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) | ||
| at java.base/java.lang.reflect.Method.invoke(Method.java:580) | ||
| at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) | ||
| at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) | ||
| at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) | ||
| at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) | ||
| at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) | ||
| at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) | ||
| at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) | ||
| at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) | ||
| at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) | ||
| at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) | ||
| at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74) | ||
| </pre> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Test failures indicate missing test resource files
All tests are failing with FileNotFoundException because the test resource files are missing from the expected location src/test/resources/. Create these files or update the test path references.
Also applies to: 125-167, 174-216, 223-265, 272-314, 321-363, 370-417
🏁 Script executed:
#!/bin/bash
# Check for the existence of test resources directory and files
echo "Checking test resources directory structure..."
ls -la book/real-world-software-development/chapter4/document-management/src/test/resources/ 2>/dev/null || echo "Test resources directory doesn't exist"
# Check if the test is looking for absolute or relative paths
echo "Checking how paths are referenced in the test class..."
grep -A 2 "importFile" book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java 2>/dev/null || echo "Test file not found"Length of output: 1321
Missing Test Resource Files – Add or Correct src/test/resources
All importFile(...) calls in DocumentManagementSystemTest are failing because the test resources directory and files don’t exist. Please either add the expected files under:
book/real-world-software-development/chapter4/document-management/src/test/resources/
or update the test constants/paths in:
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java
Test constants to provide resources for include (but may not be limited to):
LETTER→patient.letterREPORT→patient.reportXRAY→patient.xrayINVOICE→patient.invoice- any error tests (
"gobbledygook.txt",RESOURCES + "unknown.txt")
Ensure each referenced file exists at the path the test uses (relative to src/test/resources/), or adjust the test to point to your actual resource locations.
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java
around lines 76 to 118, the tests fail due to missing test resource files like
patient.letter in src/test/resources/. Fix this by either adding the required
files (patient.letter, patient.report, patient.xray, patient.invoice, etc.) to
book/real-world-software-development/chapter4/document-management/src/test/resources/
or by updating the file path constants in the test class to point to the correct
existing resource locations, ensuring all importFile calls reference valid
files.
| var spans = document.getElementById("tabs").getElementsByTagName("span"); | ||
| var codeBlocks = []; | ||
| for (var i = 0; i < spans.length; ++i) { | ||
| if (spans[i].className.indexOf("code") >= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use more reliable DOM class checking
Using indexOf to check for class names can lead to false positives. For example, if an element has the class "mycode", it would incorrectly match when checking for "code".
- if (spans[i].className.indexOf("code") >= 0) {
+ if (spans[i].classList.contains("code")) {
codeBlocks.push(spans[i]);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (spans[i].className.indexOf("code") >= 0) { | |
| if (spans[i].classList.contains("code")) { | |
| codeBlocks.push(spans[i]); | |
| } |
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/build/reports/tests/test/js/report.js
at line 55, replace the use of indexOf to check for the "code" class with a more
reliable method such as using the classList API's contains method. This ensures
only elements with the exact "code" class are matched, avoiding false positives
from partial matches like "mycode".
| private static final String RESOURCES = | ||
| "src" + File.separator + "test" + File.separator + "resources" + File.separator; | ||
| private static final String LETTER = RESOURCES + "patient.letter"; | ||
| private static final String REPORT = RESOURCES + "patient.report"; | ||
| private static final String XRAY = RESOURCES + "xray.jpg"; | ||
| private static final String INVOICE = RESOURCES + "patient.invoice"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Ensure test resource files exist.
The tests reference resource files at the specified path that will be required for the tests to run successfully. Make sure these files (patient.letter, patient.report, xray.jpg, and patient.invoice) exist in the test resources directory.
🏁 Script executed:
#!/bin/bash
# Check if the required test resource files exist
echo "Checking for test resource files..."
ls -la src/test/resources/ || echo "Resources directory not found"Length of output: 245
Missing test resource files directory
The directory src/test/resources/ is not present, so the tests won’t be able to locate the resource files. Please:
- Create the
src/test/resources/directory. - Add the following files to that directory:
patient.letterpatient.reportxray.jpgpatient.invoice
🤖 Prompt for AI Agents
In
book/real-world-software-development/chapter4/document-management/src/test/java/chpater4/DocumentManagementSystemTest.java
around lines 21 to 26, the test resource files referenced do not exist because
the directory src/test/resources/ is missing. To fix this, create the directory
src/test/resources/ in the project structure and add the required files
patient.letter, patient.report, xray.jpg, and patient.invoice to that directory
so the tests can access them properly.
실전 자바 소프트웨어 개발
문서관리 시스템
학습 키워드
→ 상속을 통해서 객체간의 관계를 표현하게 되면 Is-a 관계를 가지게 된다.
단점 : 부모의 변경이 자식에 영향이 간다. 부모 기능 중 필요하지 않는 기능까지 물려받는다.
조합 : 스프링의 주입과 같은 방식으로 필드로 추가.
필요한 기능만 선택적으로 사용할 수 있고, 여러 객체에서 재사용할 수 있다.
⇒ 상속은 변경에 유연하지 않음. 느슨하게 결합해야 변경에 유연함.
String 대신 File객체를 사용해서 오류가 발생할 확률을 줄인다.
추가로 불변객체를 사용하여, 오류가 발생하였을 때 오류 발생 원인을 축소할 수 있다.
개발자와 사용자 모두가 사용할 수 있도록 설계, 공유된 공통 언어를 의미함.
실무에서, 실무자가 사용하는 언어를 사용해야 소통하고 코드 발견성을 향상 시킬 수 있음.
디자인팀, 기획팀, 개발팀이 다른 용어를 사용하면 혼선이나 오해가 있을 수 있고 발견성이 떨어짐.
가능한 단순하게 해라
누군가 어쩌면 이런 기능이 필요할지 몰라요, Y도 할 수 있으면 좋을 텐데요 같은 말에 아니요라고 대답해야함. 좋은 의도를 가진 확장성 반드시 필요한 기능을 구현해야함. 있으면 좋은 기능을 추가하다보면 설계가 얼룩지고 복잡해짐.
클래스 상속와 인터페이스 구현을 올바르게 사용하도록 도와주는 원칙
하위 형식은 선행 조건을 더할 수 없음.
부모의 선행조건을 자식이 추가할 수 없다.
하위 형식에서 후행 조건을 약화시킬 수 없음.
특정 코드가 수행된 뒤 만족해야하는 조건을, 부모자식 모두 만족해야한다.
슈퍼 형식의 불변자는 하위 형식에서 보존됨
부모의 필드를 자식에서 변경할 수 있으면 안된다.
히스토리 규칙
자식 클래스는 부모가 예상한대로 동작의 흐름과 변경을 유지해야한다.
부모의 동작을 무력화하거나, 무의미하게 만드는건 안된다.
코드를 재사용하기 위한 세가지 방법
유틸리티 클래스
유틸클래스는 구현하기는 간편하나, 점차 여러 정적메서드를 포함하게되고 갓 클래스의 모양을 갖추는 안티패턴이 된다.
상속
재사용을 위해 상속을 사용하면 관계가 깨질 확률이 높음
도메인 클래스
상속받는 클래스가 아닌 도메인 클래스를 별도로 만들어서, 해당 클래스를 재사용하는 방법
할인 정책 같은 것을 도메인 클래스로 사용해서 정책 클래스를 많이 사용
테스트 위생
커버리지 관련된 내용, 통합 테스트만 하는 것이 옳은가? 책에서는 단위테스트를 하지 않음.
테스트 명 읽기 좋게
대체로 한글명으로도 작성하고 displayName 어노테이션으로 테스트에 대해 표현함.
실패 케이스에 대해 작성
정책상 무조건 실패해야한다면 실패케이스들 위주로 작성하는 편
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores